﻿using Draco.OWF.Exceptions;
using Draco.OWF.Metadata;
using Draco.OWF.Metadata.DataBinding;
using Draco.OWF.RT;
using Draco.OWF.RT.Engine;
using Draco.OWF.RT.Engine.Manager;
using Draco.OWF.RT.Engine.Worker;
using Draco.OWF.RT.Impl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Draco.OWF.Flow
{
    public class RunableFlow : IRunableFlow
    {
        private JobManager _jobManager = new JobManager();
        private WorkflowModel workflowModel = null;
        private ISignalActivity startActivity = null;
        private IJobContext parentContext = null;
        private IEngineContext context = null;

        public RunableFlow(WorkflowModel workflowModel, IEngineContext context)
        {
            this.workflowModel = workflowModel;
            this.context = context;
        }

        public virtual void Run(IJobContext parentContext)
        {
            this.parentContext = parentContext;
            ActivityModel starter = this.workflowModel.GetEntry();
            if (starter == null)
                throw new WorkflowException("cannot find starter activity of workflow:"+ workflowModel.Name);

            //
            String startAcType = starter.ActivityType;
            Object starterAc = context.activityManager.GetActivityInstance(startAcType);
            if(! (starterAc is ISignalActivity))
            {
                //Not a starter activity type
                throw new WorkflowException("starter activity is not instance of type Draco.OWF.ISignalActivity");
            }
            //start
            this.startActivity = starterAc as ISignalActivity;

            startActivity.Init();

            startActivity.SignalIn += SignalInHandler;

            startActivity.Active();
        }

        public virtual void Stop()
        {
            startActivity.Deactive();
        }

        protected virtual void SignalInHandler(BindingData args)
        {
            //check if is one-off signal
            if (startActivity.IsOneOffSignal)
            {
                startActivity.SignalIn -= SignalInHandler;
            }
            //start job
            IJob job = CreateJob();
            _jobManager.Add(job);
            IJobContext jobContext = CreateRTContext(parentContext);
            job.Start(jobContext, args);
        }

        protected virtual IJobContext CreateRTContext(IJobContext parent)
        {
            return new JobContext(this.workflowModel, parent);
        }

        public virtual IJob GetLastJob()
        {
            if (_jobManager.Count > 0)
                return _jobManager[_jobManager.Count - 1];
            return null;
        }

        protected IJob CreateJob()
        {
            return new Job(this.workflowModel);
        }
    }
}
